import * as vscode from 'vscode';
import axios from 'axios';
import { Logger } from './logger';
import { RemoteConfig } from './configService';
import { AuthService } from './authService';



// 自定义错误类
export class DifyApiError extends Error {
    constructor(
        message: string,
        public readonly statusCode?: number,
        public readonly response?: any
    ) {
        super(message);
        this.name = 'DifyApiError';
    }
}

export interface DifyResponse {
    answer: string;
    conversation_id: string;
    message_id: string;
    metadata?: any;
}

export interface ReviewResult {
    pass: boolean;
    reason: string;
    commitMessage: string;
}

// =====================
// 全局静态常量配置（Dify相关）
// =====================

/** Dify API 默认重试次数 */
const DIFY_API_RETRY_COUNT = 3;
/** Dify API 默认 user 字段 */
const DIFY_DEFAULT_USER = 'vscode-extension';
/** Dify API 响应最大等待时间（毫秒，10秒） */
const DIFY_API_MAX_TIMEOUT = 10000;
/** Dify API 指数退避最大等待（毫秒，10秒） */
const DIFY_API_MAX_BACKOFF = 10000;

export class DifyService {
    private apiKey: string;
    private apiEndpoint: string;
    private langChainEndpoint: string;
    private timeout: number;
    private logger = Logger.getInstance();
    private authService: AuthService;

    constructor(config: RemoteConfig, authService: AuthService) {
        this.apiKey = config.apiKey;
        this.apiEndpoint = config.apiEndpoint;
        this.langChainEndpoint = config.langChainEndpoint;
        this.timeout = config.timeout;
        this.authService = authService;
    }

    public updateConfig(config: RemoteConfig) {
        this.apiKey = config.apiKey;
        this.apiEndpoint = config.apiEndpoint;
        this.langChainEndpoint = config.langChainEndpoint;
        this.timeout = config.timeout;
    }

    public async reviewCode(changedFiles: string[], diffContent: string): Promise<ReviewResult> {
        this.logger.info(`开始代码审查: 文件数=${changedFiles.length}`);
        try {
            const files = changedFiles.map(path => ({ path }));
            const diff = await this.getDiffForFiles(files, diffContent);
            this.logger.debug(`diff内容长度: ${diff.length}`);
            
            // 打印 Dify 请求摘要
            console.log(`=== Dify 审查请求 ===`);
            console.log(`文件: ${changedFiles.join(', ')}`);
            console.log(`Diff 长度: ${diff.length} 字符`);
            console.log('---');
            
            const result = await this.checkAndGenCommitMsgWithDify(diff, DIFY_API_RETRY_COUNT);
            this.logger.info(`Dify审查结果: pass=${result.pass}, commitMessage=${result.commitMessage}`);
            return result;
        } catch (error) {
            this.logger.error('调用 Dify API 时出错', error as    Error);
            throw new Error(`获取 Dify 代码审查失败: ${error instanceof Error ? error.message : '未知错误'}`);
        }
    }

    // 新增：汇聚 commit messages 的方法
    public async aggregateCommitMessages(commitMessages: string[], filePaths: string[]): Promise<{ commitMessage: string }> {
        this.logger.info('开始汇聚 commit messages');
        try {
            // 构建请求体格式：[{"id":xxx,"summary":""},{}]
            const requestBody = commitMessages.map((message, index) => ({
                id: filePaths[index] || `file_${index}`,
                summary: message
            }));
            
            const result = await this.sendAggregationRequest(requestBody);
            return {
                commitMessage: result.commitMessage
            };
        } catch (error) {
            this.logger.error('汇聚 commit messages 失败', error as Error);
            throw new Error(`汇聚 commit messages 失败: ${error instanceof Error ? error.message : '未知错误'}`);
        }
    }

    // 新增：发送汇聚请求的方法
    private async sendAggregationRequest(requestBody: Array<{id: string, summary: string}>): Promise<{commitMessage: string}> {
        this.logger.info('发送汇聚请求到 LangChain');
        try {
            // 转换为用户指定的请求体格式
            const summaries = requestBody.map((item, index) => ({
                order: index + 1,
                summary: item.summary
            }));

            // 打印 LangChain 汇聚请求
            console.log('=== LangChain 汇聚请求 ===');
            console.log('端点: http://127.0.0.1:5000/api/workflow/commit/summarize');
            console.log(`汇聚 ${summaries.length} 个 commit messages:`);
            summaries.forEach((item, index) => {
                console.log(`  ${item.order}. ${item.summary.substring(0, 50)}${item.summary.length > 50 ? '...' : ''}`);
            });
            console.log('---');

            const res = await axios.post('http://127.0.0.1:5000/api/summarize', {
                summaries: summaries
            }, {
                headers: { 
                    'Content-Type': 'application/json'
                },
                timeout: this.timeout || DIFY_API_MAX_TIMEOUT,
                validateStatus: status => status === 200
            });

            this.logger.debug('LangChain 响应: ' + JSON.stringify(res.data));

            // 解析 LangChain 响应
            if (typeof res.data?.commitMessage === 'string') {
                return { commitMessage: res.data.commitMessage };
            }

            if (typeof res.data?.result === 'string') {
                return { commitMessage: res.data.result };
            }

            if (typeof res.data?.message === 'string') {
                return { commitMessage: res.data.message };
            }

            if (typeof res.data?.summary === 'string') {
                return { commitMessage: res.data.summary };
            }

            throw new DifyApiError('无法解析 LangChain 响应', undefined, res.data);
        } catch (error) {
            this.logger.error('LangChain 汇聚请求失败', error as Error);
            throw error;
        }
    }

    // 获取文件的差异
    private async getDiffForFiles(files: any[], diffContent: string): Promise<string> {
        if (diffContent && diffContent !== "代码变更检测") {
            return diffContent;
        }
        
        // 如果diffContent是默认值，则构建文件列表
        return files.map(f => `修改文件: ${f.path}`).join('\n');
    }

    // 检查代码并生成提交信息
    private async checkAndGenCommitMsgWithDify(
        diff: string,
        retries = DIFY_API_RETRY_COUNT
    ): Promise<ReviewResult> {
        let lastError: Error | null = null;
        
        for (let i = 0; i < retries; i++) {
            try {
                // 验证输入参数
                if (!diff.trim()) {
                    this.logger.warn('代码差异不能为空');
                    throw new DifyApiError('代码差异不能为空');
                }

                this.logger.info(`第${i + 1}次调用Dify API`);
                
                // 动态获取 user 字段
                let user = DIFY_DEFAULT_USER;
                try {
                    const userInfo = await this.authService.getCurrentUser();
                    if (userInfo && userInfo.name) {
                        user = userInfo.name;
                    }
                } catch (e) {
                    // 忽略获取用户失败，使用默认 user
                }

                // 打印 Dify 请求详情
                console.log(`=== Dify API 调用 ===`);
                console.log(`端点: ${this.apiEndpoint}`);
                console.log(`用户: ${user}`);
                console.log(`查询长度: ${diff.length} 字符`);
                console.log('---');

                const res = await axios.post(this.apiEndpoint, {
                    inputs: {},
                    query: diff,
                    conversation_id: "",
                    user
                }, {
                    headers: { 
                        'Authorization': `Bearer ${this.apiKey}`,
                        'Content-Type': 'application/json'
                    },
                    timeout: this.timeout || DIFY_API_MAX_TIMEOUT, // 使用远程配置的超时时间
                    validateStatus: status => status === 200 // 只接受 200 状态码
                });

                this.logger.debug('Dify 响应: ' + JSON.stringify(res.data));

                // 1. 处理 answer 字段
                if (typeof res.data?.answer === 'string') {
                    const parsed = this.tryParseJSON(res.data.answer);
                    if (parsed) {
                        return {
                            pass: !!parsed.pass,
                            reason: parsed.reason || '未提供原因',
                            commitMessage: parsed.commitMessage || ''
                        };
                    }
                }

                // 2. 处理直接返回的 JSON 对象
                if (typeof res.data === 'object' && (res.data.pass !== undefined || res.data.commitMessage !== undefined)) {
                    return {
                        pass: !!res.data.pass,
                        reason: res.data.reason || '未提供原因',
                        commitMessage: res.data.commitMessage || ''
                    };
                }

                // 3. 处理其他格式的响应
                let text = res.data?.message || res.data?.choices?.[0]?.message?.content || '';
                if (text) {
                    const parsed = this.tryParseJSON(text);
                    if (parsed) {
                        return {
                            pass: !!parsed.pass,
                            reason: parsed.reason || '未提供原因',
                            commitMessage: parsed.commitMessage || ''
                        };
                    }

                    // 尝试正则匹配
                    const pass = /pass\s*[:：]?\s*true/.test(text);
                    const reason = (text.match(/reason\s*[:：]?\s*([\s\S]*?)commitMessage/i)?.[1] || '未提供原因').trim();
                    const commitMessage = (text.match(/commitMessage\s*[:：]?\s*([\s\S]*)/i)?.[1] || '').trim();

                    return { pass, reason, commitMessage };
                }

                throw new DifyApiError('无法解析 Dify 响应', undefined, res.data);
            } catch (e: any) {
                this.logger.error(`Dify API 错误 (尝试${i + 1}/${retries})`, e);
                lastError = e;
                const statusCode = e.response?.status;
                const errorMessage = e.response?.data?.message || e.message;

                // 记录详细错误信息
                console.error(`Dify API 错误 (尝试 ${i + 1}/${retries}):`, {
                    statusCode,
                    message: errorMessage,
                    response: e.response?.data
                });

                // 判断是否需要重试
                const shouldRetry = (
                    i < retries - 1 && (
                        statusCode === 429 || // 限流
                        statusCode === 503 || // 服务不可用
                        statusCode === 504 || // 网关超时
                        e.code === 'ECONNABORTED' || // 请求超时
                        e.code === 'ECONNREFUSED' || // 连接被拒绝
                        e.message.includes('timeout') // 其他超时情况
                    )
                );

                if (shouldRetry) {
                    const delay = Math.min(1000 * Math.pow(2, i), DIFY_API_MAX_BACKOFF); // 指数退避，最大10秒
                    console.log(`等待 ${delay}ms 后重试...`);
                    await new Promise(resolve => setTimeout(resolve, delay));
                    continue;
                }

                // 转换为自定义错误
                throw new DifyApiError(
                    `Dify API 请求失败: ${errorMessage}`,
                    statusCode,
                    e.response?.data
                );
            }
        }
        
        this.logger.error('Dify API 最终失败', lastError || new Error('未知错误'));
        throw lastError || new DifyApiError('未知错误');
    }

    // 解析 JSON 的工具函数
    private tryParseJSON(text: string): any {
        try {
            // 尝试匹配 markdown 代码块中的 JSON
            const jsonMatch = text.match(/```json\s*(\{[\s\S]*?\})\s*```/) || 
                             text.match(/(\{[\s\S]*\})/);
            if (jsonMatch) {
                return JSON.parse(jsonMatch[1]);
            }
        } catch (e) {
            console.error('JSON 解析错误:', e);
        }
        return null;
    }

    public isConfigured(): boolean {
        // 由于配置写死在代码中，总是返回true
        return true;
    }
} 